package io.zhengsh.juc._1aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class ReentrantLockTest {


    public static void main(String[] args) {
        //lockTimeOut();
        //lockReentrant();
        //lockInterruptibly();
        demo();
    }

    private static void demo() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            log.info("lock success!");
        } finally {
            lock.unlock();
            log.info("unlock success!");
        }
    }

    // 1. 可重入
    public static void lockReentrant() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        log.info("main 线程获取锁 1 次");
        lock.lock();
        log.info("main 线程获取锁 1 次");
        lock.unlock();
        log.info("main 线程解锁 1 次");
        lock.unlock();
        log.info("main 线程解锁 1 次");
    }


    // 2. 超时失败
    public static void lockTimeOut() {
        // 1. 创建一个 ReentrantLock 实例
        ReentrantLock lock = new ReentrantLock();
        // 2. 创建线程 t1
        Thread t1 = new Thread(() -> {
            log.debug("t1 线程启动。。。。");
            try {
                // t1 尝试获取锁，锁获取超时时间 1s
                if (!lock.tryLock(1, TimeUnit.SECONDS)) {
                    log.debug("t1 线程等待 1s 后 获取锁失败");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // 如果是自己获取锁才去解锁
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }, "t1");

        // 3. 主线程获取锁
        lock.lock();
        try {
            log.debug("main 线程获取锁成功");
            // 4. 启动 t1 线程
            t1.start();
            // 5. 休眠 2s
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 如果是自己获取锁才去解锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    // 3. 可中断
    public static void lockInterruptibly() {
        ReentrantLock lock = new ReentrantLock();

        Thread t1 = new Thread(() -> {
            log.info(Thread.currentThread().getName() + " 启动。。。");
            try {
                lock.lockInterruptibly();
                log.info(Thread.currentThread().getName() + " 成功获取锁。。。");
                lock.unlock();
            } catch (InterruptedException e) {
                log.info(Thread.currentThread().getName() + " 等待锁的过程中被中断。。。");
                e.printStackTrace();
            }
        }, "t1");

        lock.lock();
        try {
            t1.start();

            log.info(Thread.currentThread().getName() + " 成功获取锁。。。");
            Thread.sleep(2000);

            t1.interrupt();
            log.info("t1 执行中断。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.info(Thread.currentThread().getName() + " 等待锁的过程中被中断。。。");
        } finally {
            lock.unlock();
        }
    }
}
